package huawei

import (
	"bufio"
	"io"
	"log"
	"net-cfg-yang-parser/oc"
	"os"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"unicode"
)

// 配置文件解析后的结构体，包含了原始的配置内容和匹配到的解析规则等信息
type CfgParserTreeNode struct {
	Parent *CfgParserTreeNode
	Children []*CfgParserTreeNode
	Content string
	Segments []string
	Line int
	Indent int

	Rule *Rule
	Key string
	XPath string
	RV reflect.Value
}

func NewCfgParserTree() *CfgParserTreeNode {
	root := new(CfgParserTreeNode)
	root.Parent = nil
	root.Children = make([]*CfgParserTreeNode, 0)
	root.Content = ""
	root.Segments = make([]string, 0)
	root.Line = -1
	root.Indent = -1
	return root
}

func ParseCfgFile(ruleFile string, cfgFile string, dev *oc.Device) error {
	var err error

	// 1. 解析规则文件
	rule, err := ParseRule(ruleFile)
	if err != nil {
		return err
	}

	// 2. 解析配置文件
	treeRootNode := NewCfgParserTree()
	treeRootNode.Rule = rule
	err = ParseCfgFileContent(cfgFile, treeRootNode)
	if err != nil {
		return err
	}

	// 3. 遍历source tree
	treeRootNode.RV = reflect.ValueOf(dev)
	TraverseCfgParserTree(treeRootNode)

	return nil
}

func ParseCfgFileContent(cfgFile string, treeRootNode *CfgParserTreeNode) error {

	file, err := os.Open(cfgFile)
	if err != nil {
		return err
	}
	defer file.Close()

	previousNode := treeRootNode
	lineNum := 1
	fileReader := bufio.NewReader(file)
	for {
		lineContent, err := fileReader.ReadString('\n')
		if err == io.EOF {
			break
		}

		currNode := ParseLine(lineContent, lineNum, previousNode)
		if currNode != nil {
			previousNode = currNode
		}

		lineNum++
	}

	return nil
}

func ParseLine(lineContent string, lineNum int, previousNode *CfgParserTreeNode) (currNode *CfgParserTreeNode) {

	indent := CalcPrefixSpaceCount(lineContent)
	trimedContent := strings.TrimSpace(lineContent)
	if strings.HasPrefix(trimedContent, "#") || trimedContent == "" {
		// 注释行或空行，不处理
		return nil
	}

	// log.Printf("line: %d, indent: %d, content: %s", lineNum, indent, lineContent)
	segments := strings.Split(trimedContent, " ")

	// 找到父节点
	parentNode := previousNode
	for parentNode.Parent != nil && indent <= parentNode.Indent {
		parentNode = parentNode.Parent
	}

	newNode := &CfgParserTreeNode{
		Parent: parentNode,
		Children: make([]*CfgParserTreeNode, 0),
		Content: lineContent,
		Segments: segments,
		Line: lineNum,
		Indent: indent,
	}

	parentNode.Children = append(parentNode.Children, newNode)

	// 查找该节点匹配的规则
	FindMatchedRule(parentNode, newNode)

	return newNode
}

func CalcPrefixSpaceCount(content string) int {

	count := 0
	for _, runeValue := range content {
		if unicode.IsSpace(runeValue) {
			count++
		} else {
			break
		}
	}

	return count
}

func FindMatchedRule(parentNode *CfgParserTreeNode, currNode *CfgParserTreeNode) {
	parentRule := parentNode.Rule
	for _, childRule := range parentRule.Children {
		matched := true
		for i, p := range childRule.Pattern {
			if len(currNode.Segments) > i {
				segment := currNode.Segments[i]
				re, _ := regexp.Compile(p)
				if !re.MatchString(segment) {
					matched = false
					break
				}
			} else {
				matched = false
				break
			}
		}

		if matched {
			// log.Printf("matched rule: %s", childRule.Pattern[0])
			currNode.Rule = childRule

			keyRule := childRule.Key
			if keyRule != nil {
				str := currNode.Segments[keyRule.Index]
				re, _ := regexp.Compile(keyRule.Pattern)
				values := re.FindAllString(str, -1)
				log.Printf("%s", values[0])
				currNode.Key = values[0]
			}

			break
		}
	}
}

func TraverseCfgParserTree(treeRootNode *CfgParserTreeNode) {

	if treeRootNode != nil && treeRootNode.Rule != nil {
		if len(treeRootNode.Content) != 0 {
			extract(treeRootNode)
		}

		for _, node := range treeRootNode.Children {
			TraverseCfgParserTree(node)
		}
	}
}

func extract(node *CfgParserTreeNode) {

	// log.Printf("extract: %s", node.Content)

	parentNode := node.Parent
	prentRV := parentNode.RV

	tv := prentRV.Elem()
	tp := tv.Type()
	ruleYangPath := node.Rule.YangPath

	// log.Printf("extract, tp: %s", tp.String())

	// 父节点的元素个数
	fieldnum := tp.NumField()
	for i := 0; i < fieldnum; i++ {
		// 与父节点的每个成员进行匹配，查找匹配的成员
		field := tp.Field(i)
		fieldValue := tv.Field(i)
		fieldYangPath := field.Tag.Get("path")
		// log.Printf("extract, fieldType: %s, fieldYangPath: %s", field.Type.String())
		if strings.HasPrefix(ruleYangPath, fieldYangPath) {
			fieldType := field.Type
			switch fieldType.Kind() {
			case reflect.Pointer:
				switch fieldType.Elem().Kind() {
				case reflect.String:

				case reflect.Uint16:

				}

			case reflect.Map:
				if fieldValue.IsNil() {
					// 创建一个新的map
					m := reflect.MakeMap(fieldType)
					fieldValue.Set(m)
				}

				// 创建一个新的元素
				v := reflect.New(fieldValue.Type().Elem().Elem())
				// log.Printf("====key: %s", node.Key)
				fieldValue.SetMapIndex(reflect.ValueOf(node.Key), v)

				node.RV = v
			}
		}

		for _, v := range node.Rule.Parameters {

			if strings.HasPrefix(v.YangPath, fieldYangPath) {
				segment := node.Segments[v.Index]
				re, _ := regexp.Compile(v.Pattern)
				parsedValue := re.Find([]byte(segment))

				fieldType := field.Type
				switch fieldType.Kind() {
				case reflect.Pointer:
					switch fieldType.Elem().Kind() {
					case reflect.String:
						v := reflect.New(fieldValue.Type().Elem())
						fieldValue.Set(v)
						v.Elem().SetString(string(parsedValue))
						node.RV = v
					case reflect.Uint16:
						v := reflect.New(fieldValue.Type().Elem())
						fieldValue.Set(v)
						uintValue, _ := strconv.ParseUint(string(parsedValue), 0, 16)
						v.Elem().SetUint(uintValue)
						node.RV = v
					}

				case reflect.Map:

				}
			}
		}
	}

}
